package com.jeejio.train.controller;

import com.jeejio.train.entity.Attach;
import com.jeejio.train.entity.Course;
import com.jeejio.train.entity.Lecturer;
import com.jeejio.train.service.AttachService;
import com.jeejio.train.service.CourseService;
import com.jeejio.train.util.IConstant;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/attach")
public class AttachController {
    private static final Logger LOG = LoggerFactory.getLogger(AttachController.class);

    @Value("${train.path.attach}")
    private String PATH_ATTACH = null;

    @Autowired
    private HttpServletRequest httpServletRequest = null;

    @Autowired
    private HttpServletResponse httpServletResponse = null;

    @Autowired
    private AttachService attachService = null;

    @Autowired
    private CourseService courseService = null;

    @RequestMapping("/findByCourse")
    public String findAttachByCourse(@RequestParam("courseId") int courseId) {
        JSONObject jResult = new JSONObject();
        try {
            Lecturer lecturer = null;
            HttpSession session = httpServletRequest.getSession();
            if (null != session) {
                lecturer = (Lecturer) session.getAttribute(IConstant.KEY_SESSION_USER);
            }

            Course course = courseService.findById(courseId);
            if ((null != lecturer)
                    && (lecturer.getId() == course.getLecturer().getId())) { // 属于当前用户的讲座
                jResult.put("allow_edit", true);
            } else {
                jResult.put("allow_edit", false);
            }

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            List<Attach> attachList = attachService.findAttachByCourse(courseId);
            jResult.put("size", attachList.size());
            JSONArray jArray = new JSONArray();
            for (Attach attach : attachList) {
                JSONObject attachJObj = new JSONObject();
                attachJObj.put("attach_id", attach.getId());
                attachJObj.put("course_id", attach.getCourseId());
                attachJObj.put("display_name", attach.getDisplayName());
                attachJObj.put("file_name", attach.getFileName());
                attachJObj.put("create_time", dateFormat.format(attach.getCreateTime()));
                jArray.put(attachJObj);
            }
            jResult.put("attach_list", jArray);
            jResult.put("state", IConstant.SUCCESS);
            jResult.put("msg", "查询成功");
        } catch (Exception e) {
            LOG.error("findAttachByCourse", e);
            jResult.put("state", IConstant.E_ATTACH_FIND_BY_COURSE);
            jResult.put("msg", e.getMessage());
        }
        return jResult.toString();
    }

    @RequestMapping("/upload")
    public String upload(@RequestParam("courseId") int courseId,
            @RequestParam("displayName") String displayName,
            @RequestParam("file") MultipartFile file) {
        JSONObject jResult = new JSONObject();

        Lecturer lecturer = null;
        HttpSession session = httpServletRequest.getSession();
        if (null == session) {
            jResult.put("state", IConstant.E_ATTACH_UPLOAD_NO_PERMISSION);
            jResult.put("msg", "请先登录再上传文件");
            return jResult.toString();
        }
        lecturer = (Lecturer) session.getAttribute(IConstant.KEY_SESSION_USER);

        try {
            Course course = courseService.findById(courseId);
            if ((null == lecturer)
                    || (lecturer.getId() != course.getLecturer().getId())) { // 只有讲座的作者才允许上传附件
                jResult.put("state", IConstant.E_ATTACH_UPLOAD_NO_PERMISSION);
                jResult.put("msg", "您没有上传附件的权限");
                return jResult.toString();
            }
        } catch (Exception e) {
            LOG.error("upload", e);
            jResult.put("state", IConstant.E_ATTACH_UPLOAD_NO_PERMISSION);
            jResult.put("msg", "鉴权失败(500)");
        }

        if (file.isEmpty()) {
            jResult.put("state", IConstant.E_ATTACH_UPLOAD_FILE_EMPTY);
            jResult.put("msg", "文件为空");
            return jResult.toString();
        }

        File courseDir = new File(PATH_ATTACH + File.separatorChar + courseId);
        if (courseDir.exists()) {
            if (!courseDir.isDirectory()) {
                if (!courseDir.delete()) {
                    jResult.put("state", IConstant.E_ATTACH_UPLOAD_RM_COURSE_FILE);
                    jResult.put("msg", "删除同名附件文件夹失败");
                }
            }
        } else {
            if (!courseDir.mkdirs()) {
                jResult.put("state", IConstant.E_ATTACH_UPLOAD_CREATE_COURSE);
                jResult.put("msg", "创建附件文件夹失败");
            }
        }

        File dest = new File(courseDir.getAbsolutePath() + File.separatorChar + UUID.randomUUID().toString());
        try {
            file.transferTo(dest);

            Attach attach = new Attach();
            attach.setCourseId(courseId);
            attach.setDisplayName(displayName);
            attach.setFileName(dest.getName());
            attach.setRelativePath(dest.getAbsolutePath().substring(0, dest.getAbsolutePath().lastIndexOf(File.separator)));
            attach.setCreateTime(new Date());
            if (attachService.upload(attach)) {
                jResult.put("state", IConstant.SUCCESS);
                jResult.put("msg", "上传成功");
            } else {
                jResult.put("state", IConstant.E_ATTACH_UPLOAD_FILE);
                jResult.put("msg", "上传失败");
            }
        } catch (IOException e) {
            LOG.error("upload", e);
            jResult.put("state", IConstant.E_ATTACH_UPLOAD_FILE);
            jResult.put("msg", "上传失败(500)");
        }
        return jResult.toString();
    }

    @RequestMapping("/downloadById")
    public void downloadById(@RequestParam("id") int id) {
        try {
            Attach attach = attachService.findByPrimaryKey(id);
            if (null == attach) {
                httpServletResponse.setStatus(404);
                httpServletResponse.setHeader("Content-Type", "text/plain; charset=utf-8");
                httpServletResponse.getOutputStream().write("此文件在数据库中不存在，请联系系统管理员"
                        .getBytes("UTF-8"));
                return;
            }

            httpServletResponse.setHeader("Content-Type", "application/octet-stream");
            httpServletResponse.setContentType("application/octet-stream");
            httpServletResponse.setHeader("Content-Disposition", "attachment;filename="
                    + URLEncoder.encode(attach.getDisplayName(), "UTF-8"));

            File src = new File(attach.getRelativePath() + File.separatorChar + attach.getFileName());
            if (!src.exists()) {
                httpServletResponse.setStatus(410);
                httpServletResponse.setHeader("Content-Type", "text/plain; charset=utf-8");
                httpServletResponse.getOutputStream().write("此文件在文件系统中不存在，请联系系统管理员"
                        .getBytes("UTF-8"));
                return;
            }
            if (!src.isFile()) {
                httpServletResponse.setStatus(410);
                httpServletResponse.setHeader("Content-Type", "text/plain; charset=utf-8");
                httpServletResponse.getOutputStream().write("此文件已损坏，请联系系统管理员"
                        .getBytes("UTF-8"));
                return;
            }
            httpServletResponse.setHeader("Content-Length", src.length() + "");
            try (FileInputStream in = new FileInputStream(src);
                 OutputStream out = httpServletResponse.getOutputStream()) {
                byte[] buf = new byte[1024 * 8];
                int len = -1;
                while ((len = in.read(buf)) >= 0) {
                    out.write(buf, 0, len);
                }
                out.flush();
            }
        } catch (Exception e) {
            LOG.error("downloadById", e);
        }
    }

    @RequestMapping("/deleteById")
    public String deleteById(@RequestParam("id") int id) {
        JSONObject jResult = new JSONObject();

        Lecturer lecturer = null;
        HttpSession session = httpServletRequest.getSession();
        if ((null == session)
            || (null == (lecturer = (Lecturer) session.getAttribute(IConstant.KEY_SESSION_USER)))) {
            jResult.put("state", IConstant.E_ATTACH_DELETE_NO_PERMISSION);
            jResult.put("msg", "您无权删除此文件");
            return jResult.toString();
        }

        try {
            int ret = attachService.deleteByPrimaryKey(id, lecturer);
            // TODO 此处应重构为采用自定义异常的方式实现
            switch (ret) {
                case IConstant.E_ATTACH_DELETE_FILE_NOT_FOUND:
                    jResult.put("msg", "此文件在数据库中不存在，请联系系统管理员");
                    break;
                case IConstant.E_ATTACH_DELETE_COURSE_NOT_FOUND:
                    jResult.put("msg", "此文件归属的课程在数据库中不存在，请联系系统管理员");
                    break;
                case IConstant.E_ATTACH_DELETE_NO_PERMISSION:
                    jResult.put("msg", "您没有删除此文件的权限");
                    break;
                case IConstant.E_ATTACH_DELETE_FAILED:
                    jResult.put("msg", "文件删除失败");
                    break;
                case IConstant.E_ATTACH_DELETE_FILE_FAILED:
                    jResult.put("msg", "次文件无法从文件系统中删除，请联系系统管理员");
                    break;
                case IConstant.SUCCESS :
                    jResult.put("msg", "删除成功");
                    break;
            }
            jResult.put("state", ret);
        } catch (Exception e) {
            LOG.error("deleteById", e);
            jResult.put("state", IConstant.E_ATTACH_DELETE_FAILED);
            jResult.put("msg", "删除失败(500)");
        }
        return jResult.toString();
    }
}
